from datetime import timedelta, datetime
from django.db import transaction
from common import models
from common.models import travelreimburse, travelreimburseordel
from Tools.mysqltools.MysqlTool import MysqlTool
from Tools.datatools import datatools

from typing import Dict, Optional
from dateutil import parser as date_parser
import re
import logging
from Tools.logtools.logtools import logfile_hander, console_handler
from datatools.datatools import clean_datetime

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
logger.addHandler(logfile_hander())
logger.addHandler(console_handler())

'''加载yaml文件'''
#^_^ 2024-12-18-shp 修改yaml
import  ruamel.yaml
def demo_config():
    """
    加载全局配置文件
    :return:
    """
    # 创建YAML对象，并指定加载类型为 'rt'（即 Round-Trip，保持原始格式）
    yaml = ruamel.yaml.YAML(typ='rt')
    #os.chdir(os.path.dirname(os.path.abspath(__file__)))
    with open("../Tools/config/config.yaml", "r") as smallfile:
        config = yaml.load(smallfile)  # pprint(config)
    return config
cfg = demo_config()


def get_reibursement_info(row_cst1,rows_cst2,ctid):
    """
    2025-02-10 shp 获取报销模块差旅报销单的基本信息
    :return:
    rows_cst2(string): 出差地点的基本信息
    row_cst(string): 报销单的基本信息
    """
    index = 0
    #从数据库拿取起止地点后，查看中途是否在乌鲁木齐有停留，如果是则直接计算住勤天数，分多段相加，如果不是，则直接计算
    stay_days = 0#总共天数
    for row in rows_cst2:
        time_difference = 0#住勤天数

        end_date = row['End_time']
        start_date = row['Start_time']
        if(row['Start_location'] != "乌鲁木齐" and index!=0): #相同地点之间的时间差值,在途天数
            time_temp = start_date - rows_cst2[index-1]['End_time']
            # 如果时间差超过1小时，则增加住勤天数
            if time_temp > timedelta(hours=1):
                time_difference = time_temp.days + 1
        difference = end_date - start_date
        stay_days += difference.days + time_difference

        #判断起始日期是否在乌鲁木齐，且在工作时间(未修复)光进行简单+1，判断时间长短如2/3
        # 5点到12点 0.333,
        # 12点到17点 0.666,
        # 17点到20点 0.999
        if row['Start_location'] == "乌鲁木齐" and datatools.is_within_working_hours(start_date):
            stay_days += datatools.check_time_and_add_value(start_date.hour)
        if row['End_location'] == "乌鲁木齐" and datatools.is_within_working_hours(end_date):
            stay_days += datatools.check_time_and_add_value(end_date.hour)
        #
        #将住勤天数和在途天数放在库中
        try:
            # 根据 id 从数据库中找到相应的记录
            t = models.travelreimburseordel.objects.get(id=row['ct2id'])
        except t.DoesNotExist:
            print(f'id 为`{t}`的表格不存在')
        t.Days_in_transit = time_difference
        t.Stayperiod = difference.days
        t.save()
        index += 1

        row['Days_in_transit'] = time_difference
        row['Stayperiod'] = difference.days

    #计算伙食补助
    foodallowance = stay_days*(float(row_cst1["dailymeal"] + row_cst1["citytransport"]))
    row_cst1['foodallowance'] = foodallowance

    #计算合计
    # 定义要相加的单元格
    cells_to_sum = [
        'ticket',  # 机票
        'cityticket',  # 住宿票
        'quarterage',  # 市内交通费单据
        'foodallowance',  # 出差补贴（注意：这里直接用了cityticket的值，可能需要调整）
        'Other_1',  # 其他1
        'Other_2',  # 其他2
        'Other_3'  # 其他3
    ]
    total_sum = 0.0

    for cell in cells_to_sum:
        if row_cst1[cell] is not None:
            try:
                total_sum += float(row_cst1[cell])
            except ValueError:
                # 如果转换失败（可能是因为单元格值不是数字），则跳过该单元格
                continue
    row_cst1['Total'] = total_sum

    # 将出差补贴放在库中
    try:
        # 根据 id 从数据库中找到相应的记录
        t = models.travelreimburse.objects.get(id=ctid)
    except t.DoesNotExist:
        print(f'id 为`{t}`的表格不存在')
    t.foodallowance = foodallowance
    t.Total = total_sum
    t.save()





    return rows_cst2,row_cst1

def get_rmb_info(ctid):
    """
    2025-02-10 shp 获取差旅报销单地点信息用于测试
    :return:
    nick_name(string): 用户姓名
    positionname(string): 职务名称
    departmentname(string):部门名称
    异常:
        抛出原生数据库异常或自定义异常
    """
    try:
        mysql = dict(cfg["doumo"]["mysql"]["database"][0])
        db = MysqlTool(ip=cfg["doumo"]["ip"], database=mysql["dbname"], user=mysql["user"], pwd=mysql["pwd"],
                   port=cfg["doumo"]["mysql"]["port"], )
        sql_query  = f"""
                    SELECT
                        ct2.Start_time,
                        ct2.End_time,
                        ct2.Start_location,
                        ct2.End_location,
                        ct2.id 'ct2id'
                    from
                        common_travelreimburse ct
                        join common_travelreimburseordel ct2 on ct.id  = ct2.Travel_Reimburse_id 
                        WHERE ct.id = {ctid}
                    ;
        """

        rows_cst2 = db.query_all(sql_query)

        sql_query=f"""
                        SELECT
                        cu.nick_name,
                        cp.positionname,
                        cd.departmentname,
                        ct.ReforBu_trip,
                        ct.ticket,
                        ct.cityticket,
                        ct.quarterage ,
                        ct.foodallowance ,
                        ct.Other_1 ,
                        ct.Other_2 ,
                        ct.Other_3 ,
                        ct.Othername_1 ,
                        ct.Othername_2 ,
                        ct.Othername_3 ,
                        ct3.dailymeal ,
                        ct3.citytransport 
                    from
                        common_travelreimburse ct
                        join common_userprofile cu on ct.userid  = cu.id 
                        join common_positions cp on cp.id = cu.positionid
                        join common_departments cd on cd.id = cu.departmentid
                        join common_travelallowance ct3 on ct3.id  = cp.tlid        
                        WHERE ct.id = {ctid}
                        ;
        """

        row_cst1 = db.query_one(sql_query)

        return rows_cst2, row_cst1
    except KeyError as e:
        logger.error(f"配置项缺失: {str(e)}")
        raise RuntimeError("系统配置错误") from e
    except ValueError as e:
        logger.warning(f"参数校验失败: {str(e)}")
        raise
    except Exception as e:
        logger.error(f"数据库操作异常: {str(e)}", exc_info=True)
        raise

def getrmbuser(userid):
    """
    2025-02-10 shp 获取用数据
    :return:
    nick_name(string): 用户姓名
    positionname(string): 职务名称
    departmentname(string):部门名称
    """
    # 根据 id 从数据库中找到相应的记录
    one_entry = models.UserProfile.objects.get(pk=userid)
    return one_entry

def select_TravelReimburse(userid):
    """
    shp 2025-04-11 拿取表中所有数据
    :param userid:用户id

    """
    reimbursements = models.travelreimburse.objects.filter(userid=userid).values(
        'id',
        'name',
        'craete_time',
    ).order_by('-craete_time')
    return reimbursements

@transaction.atomic
def save_travel_data( user, form_data):
    """
    shp 2025-04-11 统一保存差旅报销数据（包含主表+明细表）
    :param user: 用户集合
    :param form_data: 创建表单记录集合
    """

    # 创建主表记录
    main_record = create_main_record(user, form_data,form_data.get('trip_schedules', []))

    # 创建行程明细
    create_schedule_records(main_record.id, form_data.get('trip_schedules', []), user.username)

    return main_record.id

def create_main_record( user, form_data,schedules):
    """处理主表数据存储"""
    # 处理其他费用项
    additional_costs = form_data.get('additional_costs', [])
    other_names = [item.get('item_name', '') for item in additional_costs]
    other_amounts = [item.get('amount', 0) for item in additional_costs]

    # 计算所有行程明细的金额总和
    total_ticket = sum(s.get('amount', 0) for s in schedules)

    return travelreimburse.objects.create(
        name=form_data['basic_info']['document_name'],
        reforBu_trip=form_data['basic_info'].get('reason', ''),
        quarterage=form_data.get('cost_details', {}).get('accommodation', 0),
        foodallowance=form_data.get('cost_details', {}).get('meal_subsidy', 0),
        cityticket=form_data.get('cost_details', {}).get('local_transport', 0),
        ticket = total_ticket,
        userid=user.id,
        create_name=user.username,
        edit_name=user.username,
        othername_1=other_names[0] if len(other_names) > 0 else '',
        other_1=other_amounts[0] if len(other_amounts) > 0 else 0,
        othername_2=other_names[1] if len(other_names) > 1 else '',
        other_2=other_amounts[1] if len(other_amounts) > 1 else 0,
        othername_3=other_names[2] if len(other_names) > 2 else '',
        other_3=other_amounts[2] if len(other_amounts) > 2 else 0,
    )

def create_schedule_records( travel_id, schedules, username):
    """批量创建行程明细记录"""
    schedule_objs = [
        travelreimburseordel(
            travel_Reimburse_id=travel_id,
            start_time=clean_datetime(s.get('start_date')),
            end_time=clean_datetime(s.get('end_date')),
            start_location=s.get('departure'),
            end_location=s.get('destination'),
            days_in_transit=s.get('transit_days', 0),
            stayperiod=s.get('stay_days', 0),
            comment=s.get('remark', ''),
            money=s.get('amount', 0),
            create_name=username,
            edit_name=username,
        ) for s in schedules
    ]
    travelreimburseordel.objects.bulk_create(schedule_objs)

def insert_TravelReimburse(TravelReimburseData):
    """
    shp 2025-04-11在表TravelReimburse插入
    :param TravelReimburseData:需要userid和name属性
    :return:返回新创建的对象实例
    """
    try:
        new_entry = models.travelreimburse.objects.create(
            userid=TravelReimburseData.userid,
            Create_name=TravelReimburseData.name,
            Edit_name=TravelReimburseData.name,
            Craete_time=TravelReimburseData.create_time,  # 默认当前时间
            Edit_time=TravelReimburseData.edit_time,
            name=TravelReimburseData.name
        )
        return new_entry
    except Exception as e:
        # 添加详细错误日志
        logger.error(f"方法名insert_TravelReimburse插入失败: {str(e)}")
        raise  # 抛出异常供上层处理

def delete_TravelReimburse(id):
    """
    shp 2025-04-11在表TravelReimburse删除
    :param id: 表TravelReimburse的id
    :return:
    """
    try:
        models.travelreimburse.objects.filter(id=id).delete()
    except Exception as e:
        # 添加详细错误日志
        logger.error(f"方法名delete_TravelReimburse删除失败: {str(e)}")
        raise  # 抛出异常供上层处理





def insert_enhanced_ocr(ocr_data: [],user) :
    """将ocr数据写入到数据库中
    :param ocr_data: ocr读取出文件集合
    :param user: 用户集合
    """
    #数据清洗


